package fr.ema.arch3d.ref.interceptors.asm;

import java.lang.reflect.Method;

import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.fractal.julia.asm.ClassTransformer;

public class StateTraceClassTransformer extends ClassAdapter
  implements ClassTransformer
{
  private String className;

  public StateTraceClassTransformer () {
    super(null);
  }

  public void setClassVisitor (final ClassVisitor cv) {
    this.cv = cv;
  }

  public void visit (
    final int version,
    final int access,
    final String name,
    final String signature,
    final String superName,
    final String[] interfaces)
  {
    cv.visit(version, access, name, signature, superName, interfaces);
    this.className = name;

  }

  public MethodVisitor visitMethod (
    final int access,
    final String name,
    final String desc,
    final String signature,
    final String[] exceptions)
  {
    MethodVisitor v = cv.visitMethod(access, name, desc, signature, exceptions);
         
    if (v != null) {

      v = new CollectMethodTransformer(className, v);
      
    }
    return v;

  }
  


  private static class CollectMethodTransformer extends MethodAdapter
    implements Opcodes
 {
    
    private String className;
    public CollectMethodTransformer (final String className, final MethodVisitor c) {
      super(c);
      this.className = className;
    }

    public void visitCode() {
    	/*  mv.visitVarInsn(ALOAD, 0);
    	  mv.visitInsn(DUP);
    	  mv.visitFieldInsn(GETFIELD, className, "t", "I");
    	  mv.visitInsn(ICONST_3);
    	  mv.visitInsn(IADD);
    	  mv.visitFieldInsn(PUTFIELD, className, "t", "I");
    	 */
    	}

    public void visitFieldInsn (
      final int opcode,
      final String owner,
      final String name,
      final String desc)
    {     
        if (opcode == PUTFIELD ) {
        mv.visitVarInsn(ALOAD, 0);
        mv.visitLdcInsn(name);
        mv.visitLdcInsn(desc);
        mv.visitMethodInsn(
          INVOKEVIRTUAL, className, "putField", "(Ljava/lang/String;Ljava/lang/String;)V");
      }

   /*   mv.visitFieldInsn(
		         GETSTATIC, "java/lang/System", "err", "Ljava/io/PrintStream;");

		    	      // pushes the "Entering ..." String constant
		    	   
		    	    mv.visitLdcInsn(opcode+" owner= "+owner+" Field "+name);
		    	     
		    	  
		    	    // invokes the 'println' method (defined in the PrintStream class)
		    	    mv.visitMethodInsn(
		    	      INVOKEVIRTUAL,
		    	      "java/io/PrintStream",
		    	      "println",
		    	      "(Ljava/lang/String;)V");
		    	      */
		    	    
/*if(name.equals("init")) 
	{mv.visitFieldInsn(GETSTATIC, className, "Offline","I");
mv.visitFieldInsn(PUTFIELD, className, "init", "I");
		    	       }
		    	       */
		    		   
      mv.visitFieldInsn(opcode, owner, name, desc);
      
    }
    
    public void visitMethodInsn(int opc, String owner, String name,String desc){
 ;
       
    /*	if(owner.equals(interfaceName) )
        {
   
        //	mv.visitVarInsn(ALOAD, 0);
     	//mv.visitFieldInsn(GETFIELD, className, "t", "I");
        mv.visitVarInsn(ALOAD, 0);
       // mv.visitVarInsn(ALOAD, 0); 
        mv.visitLdcInsn(name);
     	mv.visitLdcInsn(desc);
        mv.visitMethodInsn(INVOKEVIRTUAL, className, "catchMethod", "(Ljava/lang/String;Ljava/lang/String;)V");
        //mv.visitFieldInsn(PUTFIELD, className, "init", "I");
   	   
   	    
   	     mv.visitFieldInsn(
		         GETSTATIC, "java/lang/System", "err", "Ljava/io/PrintStream;");

		    	      // pushes the "Entering ..." String constant
		    	
	    //mv.visitLdcInsn("opc== "+ opc+" method=="+name+" owner=="+owner+" desc="+desc);
		mv.visitLdcInsn("className="+className);    	  
		    	    // invokes the 'println' method (defined in the PrintStream class)
	    mv.visitMethodInsn(
		    	      INVOKEVIRTUAL,
		    	      "java/io/PrintStream",
		    	      "println",
		    	      "(Ljava/lang/String;)V");
       	
        
        }
       */
         mv.visitMethodInsn(opc, owner, name,desc);  
	
       		    	    
     }

    
    public void visitInsn(int opcode) {

    /*	  if ((opcode >= IRETURN && opcode <= RETURN) || opcode == ATHROW) {
    	  mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out",
    	    "Ljava/io/PrintStream;");
    	  mv.visitLdcInsn("execute ok");
    	  // invokes the 'println' method (defined in the PrintStream class)
    	  mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println",
    	    "(Ljava/lang/String;)V");

    	  }
    	*/  
    	  mv.visitInsn(opcode);
    	 }
    
    public void visitMaxs(int maxStack, int maxLocals) {
    	  mv.visitMaxs(maxStack + 20, maxLocals + 20);
    	 }
    	
 }
 /* public class FieldAdder extends ClassAdapter { 
	  private final FieldNode fn; 
	  public FieldAdder(ClassVisitor cv, FieldNode fn) {
		  super(cv); this.fn = fn; 
		  } */
 
  

}
